﻿using H;
using H.Daos;
using H.Eyes;
using H.Logs;
using H.Types;
using HMaker.Dialogs;
using HMaker.Utils;
using HModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace HMaker
{
    public partial class ImgMaker : Form
    {
        /// <summary>
        /// 用于对当前窗体的所有数据进行管理的数据源对象
        /// </summary>
        private class MyDataSource
        {
            /// <summary>
            /// 内部的Dao对象,作为当前正在处理的数据源
            /// </summary>
            public readonly IDao Dao = null;

            /// <summary>
            /// 存储已经读取的所有图片组
            /// </summary>
            public BindingSource GroupList = new BindingSource();

            /// <summary>
            /// 存储所有已经读取的图片(只读取了其中一个)
            /// </summary>
            public ImgEntity[] ImageList = null;

            public MyDataSource(IDao dao)
            {
                Dao = dao;
                Dao.UpdateTable<ImgEntity>();
                Dao.UpdateTable<ImgGrpEntity>();
                Dao.UpdateTable<ResEntity>();
            }

            /// <summary>
            /// 获取图片组
            /// </summary>
            public void LoadGroup()
            {
                GroupList.DataSource = Dao.Query<ImgGrpEntity>().Select()
                                          .Concat(new ImgGrpEntity[] { new ImgGrpEntity() { ID = null, Name = "--新建图片组--" } })
                                          .ToArray();
            }


            /// <summary>
            /// 加载图片组中的图片
            /// </summary>
            public void LoadImgs()
            {
                if (GroupList.Current is ImgGrpEntity group)
                {
                    ImageList = Dao.Query<ImgEntity>().Where("group_id", "=", group.ID).Select();
                }
            }

            /// <summary>
            /// 保存一张图片
            /// </summary>
            public void SaveImg(ImgEntity image)
            {
                Dao.Save(image);
            }

            /// <summary>
            /// 创建一个新的图片组
            /// </summary>
            public void CreateGroup(string groupName)
            {
                Dao.Save(new ImgGrpEntity() { Name = groupName }, false);
                LoadGroup();
            }

            /// <summary>
            /// 删除一张图片
            /// </summary>
            /// <param name="image"></param>
            public void DeleteImg(ImgEntity image)
            {
                Dao.Delete(image);
                ImageList = ImageList?.Except(new ImgEntity[] { image }).ToArray();
            }
        }

        /// <summary>
        /// 当前正在操作的数据源
        /// </summary>
        private MyDataSource _MyDataSource = null;

        /// <summary>
        /// 找图对象,用于找图测试,仅在需要的时候生成,如没有使用到,默认不进行加载
        /// </summary>
        private IEye _EyeInstance;

        /// <summary>
        /// 日志收集器对象
        /// </summary>
        private readonly ILogCollector LogCollector;

        /// <summary>
        /// 当前的剪切板监听实例
        /// </summary>
        private readonly ClipboardHelper Clipboard;

        /// <summary>
        /// 已经捕获的图片的列表
        /// </summary>
        private readonly BindingList<KeyValuePair<string, Bitmap>> CapturedHistoryList = new BindingList<KeyValuePair<string, Bitmap>>();

        /// <summary>
        /// 图片编辑器
        /// </summary>
        private readonly Lazy<ImgEditor> IE_Editor = new Lazy<ImgEditor>();

        /// <summary>
        /// 是否自动保存截图到文件
        /// </summary>
        private string _AutoSaveCaptureDirectory = null;

        /// <summary>
        /// 当前正在编辑的图片的模型
        /// </summary>
        public ImgEntity CurImageModel = null;

        /// <summary>
        /// 图片名称正则表达式,用于自动从图片中提取信息
        /// </summary>
        private static readonly Regex ImgNameRegex = new Regex(@"([^$]+)\$(\d+,\d+)\.bmp");

        /// <summary>
        /// 放大器
        /// </summary>
        private readonly Magnifier _Magnifier;

        /// <summary>
        /// 图片编辑器
        /// </summary>
        public ImgMaker()
        {
            InitializeComponent();

            //初始化剪切板监听
            Clipboard = new ClipboardHelper(Handle);
            Clipboard.ClipboardChanged += Clipboard_ClipboardChanged;

            //当当前选择的图片组发生改动时
            TSCB_Group.ComboBox.SelectionChangeCommitted += TSCB_Group_SelectionChangeCommitted;

            //历史记录信息
            CB_History.DataSource = CapturedHistoryList;
            CapturedHistoryList.ListChanged += CapturedHistoryList_ListChanged;

            //当选择图片时
            ILV_Main.SelectObjectChanged += ILV_Main_SelectObjectChanged;

            KeyPreview = true;

            UpdateEnabled();

            //初始化日志收集器
            LogCollector = HService.DefaultLoggerFactory.Value.GetInstance();

            _Magnifier = new Magnifier(this)
            {
                Location = Location.Add(Width, 0)
            };
        }




        /// <summary>
        /// 刷新ListView中的数据
        /// </summary>
        private void RefreshListView()
        {
            ILV_Main.ResetList(_MyDataSource.ImageList);
        }


        /// <summary>
        /// UI可用性控制
        /// </summary>
        private void UpdateEnabled()
        {
            TS_Main.Enabled = P_Main.Enabled = _MyDataSource != null;
        }

        /// <summary>
        /// 加载数据库文件
        /// </summary>
        /// <param name="dbFile"></param>
        private void LoadDb(string dbFile)
        {
            _MyDataSource = new MyDataSource(HService.DefaultDaoFactory.Value.CreateInstance(dbFile, null, false));

            _MyDataSource.GroupList.CurrentChanged += GroupList_CurrentChanged;

            _MyDataSource.LoadGroup();
            ComboBox cbGroup = TSCB_Group.ComboBox;
            cbGroup.DataSource = _MyDataSource.GroupList;
            cbGroup.DisplayMember = "Name";
            cbGroup.ValueMember = "ID";

            UpdateEnabled();
        }

        private void UnloadDb()
        {
            _MyDataSource = null;
            TSCB_Group.ComboBox.DataSource = null;
            UpdateEnabled();
            GC.Collect(2);
        }

        /// <summary>
        /// 加载一张图片作为背景
        /// </summary>
        /// <param name="bitmap"></param>
        private void LoadBitmap(Bitmap bitmap)
        {
            if (bitmap == null)
            {
                return;
            }

            string name = $"截图{DateTime.Now.Ticks}.bmp";
            CapturedHistoryList.Insert(0, new KeyValuePair<string, Bitmap>(name, bitmap));

            if (CapturedHistoryList.Count > 10)
            {
                //如果数量大于10,则去掉最后一张,保持有十条记录
                CapturedHistoryList.RemoveAt(10);
            }
        }


        /// <summary>
        /// 加载识图插件
        /// </summary>
        private IEye LoadEye()
        {
            if (_EyeInstance == null)
            {
                _EyeInstance = HService.DefaultEyeFactory.Value.CreateInstance();
                _EyeInstance.DefaultOption.DeletaColor = new H.Types.RGB(0);
            }
            return _EyeInstance;
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            Clipboard?.ProcessClipboard(ref m);
        }

        #region 事件响应函数

        private void ImgMaker_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyData)
            {
                case Keys.Up:
                    Cursor.Position = Cursor.Position.Add(0, -1);
                    e.SuppressKeyPress = false;
                    break;
                case Keys.Down:
                    Cursor.Position = Cursor.Position.Add(0, 1);
                    e.SuppressKeyPress = false;
                    break;
                case Keys.Left:
                    Cursor.Position = Cursor.Position.Add(-1, 0);
                    e.SuppressKeyPress = false;
                    break;
                case Keys.Right:
                    Cursor.Position = Cursor.Position.Add(1, 0);
                    e.SuppressKeyPress = false;
                    break;
                case Keys.Add | Keys.Control:
                case Keys.Oemplus | Keys.Control:
                    _Magnifier.Scalar += 2;
                    e.SuppressKeyPress = false;
                    break;
                case Keys.Subtract | Keys.Control:
                case Keys.OemMinus | Keys.Control:
                    _Magnifier.Scalar -= 2;
                    e.SuppressKeyPress = false;
                    break;
                case Keys.Apps:
                    Point point = PS_Main.PointToClient(Cursor.Position);
                    LastContextArgs = new Events.ContextMenuNeededEventArgs()
                    {
                        LocationInBG = PS_Main.PointToBG(Cursor.Position),
                        Location = point
                    };
                    CMS_BG.Show(PS_Main, point);
                    break;

            }
        }

        private void CapturedHistoryList_ListChanged(object sender, ListChangedEventArgs e)
        {
            if (CB_History.Items.Count > 0)
            {
                CB_History.SelectedIndex = -1;
                CB_History.SelectedIndex = 0;
            }
        }

        private void Clipboard_ClipboardChanged(IDataObject data)
        {
            if (TSBN_EnableCapture.Checked && _MyDataSource != null)
            {
                if (data.GetDataPresent(DataFormats.Bitmap))
                {
                    string name = $"截图{DateTime.Now.Ticks}.png";
                    Bitmap bitmap = (Bitmap)data.GetData(DataFormats.Bitmap, true);
                    CapturedHistoryList.Insert(0, new KeyValuePair<string, Bitmap>(name, bitmap));
                    if (_AutoSaveCaptureDirectory != null)
                    {
                        bitmap.Save(Path.Combine(_AutoSaveCaptureDirectory, name), ImageFormat.Png);
                    }

                    if (CapturedHistoryList.Count > 10)
                    {
                        //如果数量大于10,则去掉最后一张,保持有十条记录
                        CapturedHistoryList.RemoveAt(10);
                    }
                }
            }
        }

        private void TSCB_Group_SelectionChangeCommitted(object sender, EventArgs e)
        {
            if (TSCB_Group.ComboBox.SelectedItem is ImgGrpEntity value)
            {
                if (value.ID == null)
                {
                    GroupEditor editor = new GroupEditor();
                    if (editor.ShowDialog() == DialogResult.OK)
                    {
                        _MyDataSource.CreateGroup(editor.GroupName);
                    }
                }
                else
                {
                    _MyDataSource.LoadImgs();
                    RefreshListView();
                }
            }
        }

        private void GroupList_CurrentChanged(object sender, EventArgs e)
        {
            if (_MyDataSource.GroupList.Current is ImgGrpEntity model && model.ID.HasValue)
            {
                _MyDataSource.LoadImgs();
                RefreshListView();
            }
        }


        private void TSMI_CreateFile_Click(object sender, EventArgs e)
        {
            if (SFD_HDB.ShowDialog() == DialogResult.OK)
            {
                if (File.Exists(SFD_HDB.FileName))
                {
                    File.Delete(SFD_HDB.FileName);
                }
                LoadDb(SFD_HDB.FileName);
            }
        }

        private void TSMI_OpenFile_Click(object sender, EventArgs e)
        {
            if (OFD_HDB.ShowDialog() == DialogResult.OK)
            {
                LoadDb(OFD_HDB.FileName);
            }
        }

        private void TSMI_CloseFile_Click(object sender, EventArgs e)
        {
            UnloadDb();
        }

        private void TSBN_EnableCapture_CheckStateChanged(object sender, EventArgs e)
        {
            if (TSBN_EnableCapture.Checked)
            {
                TSBN_EnableCapture.Image = MyRes.CaptureL16;
                TSBN_EnableCapture.ToolTipText = "自动从剪切板获取图片(启用)";
            }
            else
            {
                TSBN_EnableCapture.Image = MyRes.CaptureD16;
                TSBN_EnableCapture.ToolTipText = "自动从剪切板获取图片(禁用)";
            }
        }

        private void Bn_ClearHistory_Click(object sender, EventArgs e)
        {
            CapturedHistoryList.Clear();
            GC.Collect(2);
        }

        private void CB_History_SelectedValueChanged(object sender, EventArgs e)
        {
            if (CB_History.SelectedItem is KeyValuePair<string, Bitmap> item)
            {
                PS_Main.BG = item.Value;
                _Magnifier.SetImage(item.Value);
            }
        }

        private void PS_Main_OnSelectedAreaChanged(object sender, Events.SelectedAreaChangedEventArgs e)
        {
            CurImageModel = null;
            PB_Preview.Image = e.Bitmap;
            _Magnifier.SetSize(e.Area.Size);
        }

        private void PS_Main_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
            {
                e.Effect = DragDropEffects.Copy;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void PS_Main_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop) && e.Data.GetData(DataFormats.FileDrop, true) is string[] filenames)
            {
                foreach (string fileName in filenames)
                {
                    try
                    {
                        LoadBitmap(new Bitmap(fileName));
                    }
                    catch (Exception) { }
                }
            }
        }


        private void PB_Preview_Click(object sender, EventArgs e)
        {
            ImgEditor editor = IE_Editor.Value;
            if (PB_Preview.Image != null)
            {
                ImgEntity editing = CurImageModel ?? new ImgEntity() { Bin = BitmapUtils.ToBytes((Bitmap)PB_Preview.Image) };
                if (TSCB_Group.ComboBox.SelectedItem is ImgGrpEntity group)
                {
                    editing.GroupID = group.ID;
                }
                else
                {
                    MessageBox.Show(this, "必须先选择图片组");
                    return;
                }

                editor.ImgEntity = editing;
                if (editor.ShowDialog() == DialogResult.OK)
                {
                    CurImageModel = editor.ImgEntity;
                    PB_Preview.Image = BitmapUtils.FromBytes(CurImageModel.Bin);
                    _MyDataSource.SaveImg(CurImageModel);
                    _MyDataSource.LoadImgs();
                    RefreshListView();
                }
            }
        }

        private void ILV_Main_SelectObjectChanged(object sender, Events.SelectItemArgs<ImgEntity> e)
        {
            CurImageModel = ILV_Main.CurObject;
            if (CurImageModel != null)
            {
                PB_Preview.Image = BitmapUtils.FromBytes(CurImageModel.Bin);
            }
            else
            {
                PB_Preview.Image = null;
            }
        }

        private void TSMI_AutoSave_Click(object sender, EventArgs e)
        {
            if (_AutoSaveCaptureDirectory != null)
            {
                _AutoSaveCaptureDirectory = null;
                TSMI_AutoSave.Checked = false;
            }
            else
            {
                if (FBD_SaveCapature.ShowDialog() == DialogResult.OK)
                {
                    if (Directory.Exists(FBD_SaveCapature.SelectedPath))
                    {
                        _AutoSaveCaptureDirectory = FBD_SaveCapature.SelectedPath;
                        TSMI_AutoSave.Checked = true;
                    }
                    else
                    {
                        MessageBox.Show(this, "错误", "请选择有效目录");
                    }
                }
            }
        }

        private void TSMI_LoadCapture_Click(object sender, EventArgs e)
        {
            OFD_Img.DefaultExt = ".bmp";
            if (OFD_Img.ShowDialog() == DialogResult.OK)
            {
                LoadBitmap(new Bitmap(OFD_Img.FileName));
            }
        }


        private void TSMI_OpenResAllocator_Click(object sender, EventArgs e)
        {
            if (_MyDataSource != null)
            {
                new ResAllocator(_MyDataSource.Dao, LogCollector).Show();
            }
            else
            {
                MessageBox.Show(this, "请先打开资源文件", "提示");
            }
        }

        private void TSMI_Exit_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void TSMI_EditImg_Click(object sender, EventArgs e)
        {
            PB_Preview_Click(sender, e);
        }

        private void TSMI_ExportImg_Click(object sender, EventArgs e)
        {
            if (CurImageModel == null || CurImageModel.Bin == null)
            {
                return;
            }

            SFD_Img.FileName = $"{CurImageModel.Name}${CurImageModel.BaseOffsetStr}.bmp";

            if (SFD_Img.ShowDialog() == DialogResult.OK)
            {
                using (Stream stream = SFD_Img.OpenFile())
                {
                    stream.Write(CurImageModel.Bin, 0, CurImageModel.Bin.Length);
                }
            }
        }

        private void TSMI_DeleteImg_Click(object sender, EventArgs e)
        {
            if (CurImageModel == null)
            {
                return;
            }
            _MyDataSource.DeleteImg(CurImageModel);
            RefreshListView();
        }


        private void TSMI_ImportImg_Click(object sender, EventArgs e)
        {
            if (OFD_Img.ShowDialog() == DialogResult.OK)
            {
                foreach (string file in OFD_Img.FileNames)
                {
                    FileInfo fileInfo = new FileInfo(file);
                    ImgEntity img = new ImgEntity();
                    Match match = ImgNameRegex.Match(Path.GetFileName(file));
                    if (match.Success)
                    {
                        img.Name = match.Groups[1].Value;
                        img.BaseOffsetStr = match.Groups[2].Value;
                    }
                    else
                    {
                        img.Name = "导入图片_" + fileInfo.CreationTime.Ticks;
                    }
                    _MyDataSource.SaveImg(img);
                }
            }
        }

        private void TSMI_RefreshList_Click(object sender, EventArgs e)
        {
            _MyDataSource.LoadImgs();
            RefreshListView();
        }

        #endregion

        /// <summary>
        /// 基准点偏移
        /// </summary>
        private Point _BasePoint;

        /// <summary>
        /// 上一次需要上下文菜单时传递的参数
        /// </summary>
        private Events.ContextMenuNeededEventArgs LastContextArgs = null;

        private void PS_Main_OnContextMenuNeeded(object sender, Events.ContextMenuNeededEventArgs e)
        {
            LastContextArgs = e;
            CMS_BG.Show(PS_Main, e.Location);
        }

        private void PS_Main_BGMouseMove(object sender, MouseEventArgs e)
        {
            _Magnifier.SetCurPos(e.Location);
        }

        private void TSMI_SetAsBase_Click(object sender, EventArgs e)
        {
            _BasePoint = LastContextArgs.LocationInBG;
            _Magnifier.SetBasePos(LastContextArgs.LocationInBG);
        }

        private void TSB_Base_Click(object sender, EventArgs e)
        {
            _BasePoint = Point.Empty;
            _Magnifier.SetBasePos(Point.Empty);
        }

        private void TSMI_CopyPoint_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Clipboard.SetText(LastContextArgs.LocationInBG.Sub(_BasePoint).MakeString());
        }

        private void TSMI_CopyRectXYWH_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Clipboard.SetText(LastContextArgs.Rect.Sub(_BasePoint).MakeString());
        }

        private void TSMI_CopyRectLTRB_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Clipboard.SetText(LastContextArgs.Rect.Sub(_BasePoint).MakeLTRB());
        }

        private void TSMI_FindPic_Click(object sender, EventArgs e)
        {
            if (PS_Main.BG == null)
            {
                MessageBox.Show(this, "必须先截图或加载背景图片");
                return;
            }
            if (CurImageModel == null)
            {
                MessageBox.Show("必须选择一张图片进行匹配");
                return;
            }
            Bitmap bg = PS_Main.BG;

            IEye eye = LoadEye();
            using (MemoryStream ms = new MemoryStream())
            {
                bg.Clone(new Rectangle(Point.Empty, bg.Size), PixelFormat.Format24bppRgb).Save(ms, ImageFormat.Bmp);
                if (!eye.SetDisplay(ms.ToArray()))
                {
                    MessageBox.Show("背景图片不合法,无法进行查找");
                    return;
                }
                Rect rect = new Rect(0, 0, bg.Width, bg.Height);

                if (eye.FindPic(CurImageModel).See(rect, out Pos[] pos) != null)
                {
                    new FindPicResultDialog(_BasePoint, (from i in pos select new Point(i.X, i.Y)).ToArray()).Show();
                }
                else
                {
                    MessageBox.Show("很抱歉,没有找到匹配");
                }
            }
        }

        private void CMS_Main_Opening(object sender, CancelEventArgs e)
        {
            TSMI_EditImg.Enabled = TSMI_ExportImg.Enabled = TSMI_DeleteImg.Enabled = CurImageModel != null;
            TSMI_FindPic.Enabled = CurImageModel != null && PS_Main.BG != null;
        }



        private void TSB_Magnifier_Click(object sender, EventArgs e)
        {
            TSB_Magnifier.Checked = !TSB_Magnifier.Checked;
            if (TSB_Magnifier.Checked)
            {
                TSB_Magnifier.ToolTipText = "启用放大镜";
                TSB_Magnifier.Image = MyRes.Magnifier16Bright;

                _Magnifier.Show();
            }
            else
            {
                TSB_Magnifier.ToolTipText = "禁用放大镜";
                TSB_Magnifier.Image = MyRes.Magnifier16Dark;
                _Magnifier.Hide();
            }
        }
    }
}
